//
//  DataBindManage.m
//  DataBind
//
//  Created by Super on 2019/12/16.
//  Copyright © 2019 Super. All rights reserved.
//

#import "DataBindManage.h"
#import "Aspects.h"
#import "DataBindModel.h"
#import "UIViewController+DataBind.h"

#import "UIView+DataBind.h"
#import "UpdatePropertyDataModel.h"

@implementation DataBindManage

+ (void)setup {
    NSString *className = @"UIViewController";
    Class class = NSClassFromString(className);
    
    [DataBindManage initDataBindRegisterListWithClass:class];
    [DataBindManage unbindWithClass:class];
    [DataBindManage observeValueWithClass:class];
}

//绑定数组初始化
+ (void)initDataBindRegisterListWithClass:(Class)class {
    [class aspect_hookSelector:@selector(viewDidLoad) withOptions:AspectPositionAfter usingBlock:^(id<AspectInfo> aspectInfo) {
      UIViewController *vc = aspectInfo.instance;
      vc.dataBindRegisterList = [NSMutableArray array];
    } error:NULL];
}

//解除绑定
+ (void)unbindWithClass:(Class)class {
    [class aspect_hookSelector:NSSelectorFromString(@"dealloc") withOptions:AspectPositionBefore usingBlock:^(id<AspectInfo> aspectInfo) {
      UIViewController *vc = aspectInfo.instance;
      for (NSDictionary *dict in vc.dataBindRegisterList) {
          UIViewController *observer = [dict objectForKey:@"observer"];
          if (observer == vc) {
              [vc unBindWithOldBindInfo:dict];
          } else {
              NSLog(@"注意存在内存泄露");
          }
      }
    } error:NULL];
}

//数据改动监听
+ (void)observeValueWithClass:(Class)class {
    [class aspect_hookSelector:@selector(observeValueForKeyPath:ofObject:change:context:) withOptions:AspectPositionAfter usingBlock:^(id<AspectInfo> aspectInfo) {
        UIViewController *vc = aspectInfo.instance;
        NSArray *array = aspectInfo.arguments; //参数
        
        NSString *keyPath = nil;
        id object = nil;
        NSDictionary *change = nil;
        if (array.count >= 4) {
            keyPath = array[0];
            object = array[1];
            change = array[2];
        } else {
            NSLog(@"观察者数据有误");
            return;
        }
        
        BOOL hasMatchView = false; //已匹配到响应视图
        for (NSDictionary *dict in vc.dataBindRegisterList) {
            NSNumber *bindType = [dict objectForKey:@"bindType"];
            
            switch (bindType.intValue) {
                case BindViewAndModel:
                    if (!hasMatchView) {
                        [self updateViewDataIfNeed:dict object:object keyPath:keyPath change:change];
                    }
                    [self updateModelOrPropertyDataIfNeed:dict object:object keyPath:keyPath change:change];
                    break;
                case BindViewToModel:
                    [self updateViewDataIfNeed:dict object:object keyPath:keyPath change:change];
                    break;
                case BindModelToView:
                     [self updateModelOrPropertyDataIfNeed:dict object:object keyPath:keyPath change:change];
                    break;
                default:
                    break;
            }
            
            //当仅做了视图绑定Model 且已匹配到视图 停止匹配
            if (hasMatchView && bindType.intValue == BindViewToModel) {
                break;
            }
        }
    } error:NULL];
}

//更新来自视图的数据  同步到model或者属性 返回值为匹配到绑定的数据
+ (BOOL)updateViewDataIfNeed:(NSDictionary *)bindInfo object:(id)object keyPath:(NSString *)keyPath change:(NSDictionary *)change {
    UIView *view = [bindInfo objectForKey:@"bindUI"];
    NSString *uiBindProp = [bindInfo objectForKey:@"UIBindProp"];
    
    if ([uiBindProp isEqualToString:keyPath] && object == view) {
        NSString *isProperty = [bindInfo objectForKey:@"isProperty"];
        if (isProperty.intValue) {
            [self updateViewDataToProperty:bindInfo object:object keyPath:keyPath change:change];
        } else {
            [self updateViewDataToModel:bindInfo object:object keyPath:keyPath change:change];
        }
        return true;
    } else {
        return false;
    }
}

//更新来自视图的数据  同步到model
+ (void)updateViewDataToModel:(NSDictionary *)bindInfo object:(id)object keyPath:(NSString *)keyPath change:(NSDictionary *)change {
    DataBindModel *model = [bindInfo objectForKey:@"model"];
    NSString *key = [bindInfo objectForKey:@"modelKey"];
    id value = [change objectForKey:@"new"];
    
    [UpdatePropertyDataModel updateValueWith:model key:key value:value];
}

//更新来自视图的数据  同步到属性
+ (void)updateViewDataToProperty:(NSDictionary *)bindInfo object:(id)object keyPath:(NSString *)keyPath change:(NSDictionary *)change {
    UIViewController *vc = [bindInfo objectForKey:@"observer"];
    NSString *propertyKey = [bindInfo objectForKey:@"propertyKey"];
    id value = [change objectForKey:@"new"];
    
    [UpdatePropertyDataModel updateValueWith:vc key:propertyKey value:value];
}

//更新来自model或者属性数据 在view上渲染
+ (void)updateModelOrPropertyDataIfNeed:(NSDictionary *)bindInfo object:(id)object keyPath:(NSString *)keyPath change:(NSDictionary *)change {
    NSString *isProperty = [bindInfo objectForKey:@"isProperty"];
    if (isProperty.intValue) {
        [self updatePropertyDataIfNeed:bindInfo object:object keyPath:keyPath change:change];
    } else {
        [self updateModelDataIfNeed:bindInfo object:object keyPath:keyPath change:change];
    }
}

+ (void)updateModelDataIfNeed:(NSDictionary *)bindInfo object:(id)object keyPath:(NSString *)keyPath change:(NSDictionary *)change {
    DataBindModel *model = [bindInfo objectForKey:@"model"];
    NSString *key = [bindInfo objectForKey:@"modelKey"];

    if ([key isEqualToString:keyPath] && object == model) {
        UIView *view = [bindInfo objectForKey:@"bindUI"];
        NSString *UIBindProp = [bindInfo objectForKey:@"UIBindProp"];
        id value = [change objectForKey:@"new"];
        [view updateChange:UIBindProp value:value];
    }
}

+ (void)updatePropertyDataIfNeed:(NSDictionary *)bindInfo object:(id)object keyPath:(NSString *)keyPath change:(NSDictionary *)change {
    NSString *propertyKey = [bindInfo objectForKey:@"propertyKey"];
    UIViewController *vc = [bindInfo objectForKey:@"observer"];
    if ([propertyKey isEqualToString:keyPath] && object == vc) {
        UIView *view = [bindInfo objectForKey:@"bindUI"];
        NSString *UIBindProp = [bindInfo objectForKey:@"UIBindProp"];
        id value = [change objectForKey:@"new"];
        [view updateChange:UIBindProp value:value];
    }
}

@end
